//==============================================================================================================
//	|		   >>>>>>>>>>>>>>>>>> LIBRARIES <<<<<<<<<<<<<<<<<<			|					
//==============================================================================================================
#include "config.h"
//------------------------------------------------------------------------------------------------------------
#include <stdlib.h>
#include <assert.h>
//------------------------------------------------------------------------------------------------------------
#include "stack_t.h"
#include "define_constructions.h"
//==============================================================================================================
//==============================================================================================================


//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//	|		  	 >>>>>>>>>>>>>>>>>> CODE <<<<<<<<<<<<<<<<<<			|					
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


//==============================================================================================================
struct stack_t* stack_constructor (const int target_size_to_create)
{
  INCR_INDENT;
  INDENT (OUT ("# called stack constructor.\n"));

  assert (target_size_to_create > 0);

  struct stack_t* target_stack = NULL;
  target_stack = (stack_t*) calloc (1, sizeof (stack_t));
  assert (target_stack);

  target_stack -> data = NULL;
  target_stack -> data = (int*) calloc (target_size_to_create, sizeof (int));
  assert (target_stack -> data);

  target_stack -> max_size = target_size_to_create;
  target_stack -> cure_size = 0;

  DECR_INDENT;
  return target_stack;
}

//==============================================================================================================
short int stack_destructor (struct stack_t *target_stack)
{
  INCR_INDENT;
  INDENT (OUT ("#  called stack [ %p ] destructor\n", target_stack -> data));

  assert (target_stack);

  const short int POISON = -666;

  for (register int  i = 0; i < (target_stack -> max_size); i++)
    target_stack -> data [i] = POISON;

  target_stack -> cure_size = POISON;
  target_stack -> max_size  = POISON;

  free (target_stack -> data);
  target_stack -> data = NULL;

  free (target_stack);
  target_stack = NULL;

  DECR_INDENT;
  return 0;
}

//==============================================================================================================
short int stack_is_ok (const struct stack_t *target_stack)
{
  INCR_INDENT;
  INDENT (OUT ("#  called stack is ok\n"));

  assert (target_stack);

  DECR_INDENT;

  return ((target_stack != NULL)
          &&
          (target_stack -> data != NULL)
          &&
          (target_stack -> cure_size >= 0)
          &&
          (target_stack -> cure_size <= target_stack -> max_size)
          );
}

//==============================================================================================================
short int stack_is_empty (const struct stack_t *target_stack)
{
  INCR_INDENT;
  INDENT (OUT ("#  called stack_is_empty\n"));

  assert (target_stack);

  DECR_INDENT;

  return ( target_stack -> cure_size  <=  0);
}

//==============================================================================================================
short int stack_is_full (const struct stack_t *target_stack)
{
  INCR_INDENT;
  INDENT (OUT ("#  called stack_is_full\n"));

  assert (target_stack);

  DECR_INDENT;

  return ( target_stack -> cure_size  >=  target_stack -> max_size);
}

//==============================================================================================================
short int stack_push (struct stack_t *target_stack, const int value)
{
  INCR_INDENT;
  INDENT (OUT ("#  called stack_push with stack [ %p ] and value [ %d ]\n", target_stack -> data, value));

  assert (target_stack);

  if (stack_is_ok (target_stack) != 1) return -1;
  if (stack_is_full (target_stack) == 1) return 1;

  target_stack -> data[(target_stack -> cure_size)++] = value;

  if (stack_is_ok (target_stack) != 1) return -1;

  DECR_INDENT;

  return 0;
}

//==============================================================================================================
short int stack_pop (struct stack_t *target_stack, int *target_place)
{
  INCR_INDENT;
  INDENT (OUT ("#  called stack_pop with stack [ %p ]\n", target_stack -> data));

  assert (target_stack);
  assert (target_place);

  if (stack_is_ok (target_stack) != 1) return -1;
  if (stack_is_empty (target_stack) == 1) return 1;

  *target_place  =  target_stack -> data[--(target_stack -> cure_size)];

  if (stack_is_ok (target_stack) != 1) return -1;

  DECR_INDENT;

  return 0;
}

